package com.hcnetsdk.jna;

import android.util.Log;

import com.hikvision.netsdk.HCNetSDK;
import com.hikvision.netsdk.NET_DVR_DEVICEINFO_V30;
import com.hikvision.netsdk.NET_DVR_PREVIEWINFO;
import com.hikvision.netsdk.RealPlayCallBack;

import org.MediaPlayer.PlayM4.Player;
import org.MediaPlayer.PlayM4.PlayerCallBack;

/**
 * 作者：Administrator on 2019/3/7 17:57
 * 邮箱：9611153@qq.com
 *
 *

 public void startIPC() {
 trtcCloud.stopLocalPreview();//

 trtcCloud.enableCustomVideoCapture(true);
 HCNetSource.getInstance(new HCNetSource.IIpcDataFunc(){
@Override
public void afterCall(int dataLen, byte[] data, int nWidth, int nHeight, int nFrameTime) {
if (trtcCloud != null) {
TRTCCloudDef.TRTCVideoFrame var1 = new TRTCCloudDef.TRTCVideoFrame();
var1.pixelFormat = TRTCCloudDef.TRTC_VIDEO_PIXEL_FORMAT_I420;
var1.data = data;
var1.height = nWidth;
var1.width = nHeight;
var1.timestamp = nFrameTime;
trtcCloud.sendCustomVideoData(var1); //todo trtcsdk腾讯音视频接入ipc，未显示本地
} else {
Log.d(TAG, "sdk setIpcDataFunc trtcCloud==null");
}
}
}).startSinglePreview();
 }


 public void stopIPC() {
 HCNetSource.getInstance(null).stopSinglePreview();

 if (trtcCloud != null) {
 trtcCloud.enableCustomVideoCapture(false);

 TXCloudVideoView localVideoView = mVideoViewLayout.getCloudVideoViewByIndex(1);
 localVideoView.setUserId(trtcParams.userId);
 localVideoView.setVisibility(View.VISIBLE);
 trtcCloud.setLocalViewFillMode(TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FILL);
 trtcCloud.startLocalPreview(true, localVideoView);
 }
 }
 */
public class HCNetSource {
    private static final String TAG = HCNetSource.class.getSimpleName();

    private static HCNetSource instance = null;

    public class CameraInfo {
        public int id;
        public String address;
        public int port;
        public String account;
        public String password;
        public String name;
    }

    private CameraInfo camera;

    private void setCameraInfo() {
        camera = new CameraInfo();
        camera.id = 100;
        camera.address = "192.168.0.100";
        camera.port = 8000;
        camera.account = "admin";
        camera.password = "ss123456";
        camera.name = "admin";
    }

    private int m_iStartChan = 0; // start channel no
    private int m_iChanNum = 0; // channel number

    public int m_iLogID = -1; // return by NET_DVR_Login_v30
    private int m_iPreviewHandle = -1;
    private int m_iPort = -1; // play port


    private IIpcDataFunc callback;

    public void setIpcDataFunc(IIpcDataFunc funcData) {
        callback = funcData;
    }

    public interface IIpcDataFunc {
        void afterCall(int dataLen, byte[] data, int nWidth, int nHeight, int nFrameTime);
    }

    public static HCNetSource getInstance(IIpcDataFunc funcData) {
        if (instance == null) {
            instance = new HCNetSource();
            instance.setIpcDataFunc(funcData);
        }
        return instance;
    }

    private void stopPlayer() {
        Player.getInstance().stopSound();
        // player stop play
        if (!Player.getInstance().stop(m_iPort)) {
            Log.e(TAG, "stop is failed!");
            return;
        }
        Player.getInstance().setDecodeCB(m_iPort,null);

        if (!Player.getInstance().closeStream(m_iPort)) {
            Log.e(TAG, "closeStream is failed!");
            return;
        }
        if (!Player.getInstance().freePort(m_iPort)) {
            Log.e(TAG, "freePort is failed!" + m_iPort);
            return;
        }

        m_iPort = -1;
    }
    public void stopSinglePreview() {
        stopPlayer();

        HCNetSDK.getInstance().NET_DVR_StopRealPlay(m_iPreviewHandle);
        HCNetSDK.getInstance().NET_DVR_Logout_V30(m_iLogID);

        // release net SDK resource
        HCNetSDK.getInstance().NET_DVR_Cleanup();
    }

    public void startSinglePreview() {

        setCameraInfo();
        HCNetSDK.getInstance().NET_DVR_Init();
        m_iLogID = loginNormalDevice();
        if (m_iLogID < 0) return;

        RealPlayCallBack fRealDataCallBack = getRealPlayerCbf();
        NET_DVR_PREVIEWINFO previewInfo = new NET_DVR_PREVIEWINFO();
        previewInfo.lChannel = m_iStartChan;
        previewInfo.dwStreamType = 1; // substream 0 表示主码流，为 1 表示子码流
        previewInfo.bBlocked = 1;// 0- 非阻塞取流，1- 阻塞取流
        previewInfo.hHwnd = null;

        m_iPreviewHandle = HCNetSDK.getInstance().NET_DVR_RealPlay_V40(m_iLogID, previewInfo, fRealDataCallBack);
        if (m_iPreviewHandle < 0) {
            Log.e(TAG, "NET_DVR_RealPlay is failed!Err:" + HCNetSDK.getInstance().NET_DVR_GetLastError());
        }

    }

    private int loginNormalDevice() {
        // get instance
        NET_DVR_DEVICEINFO_V30 m_oNetDvrDeviceInfoV30 = null;
        m_oNetDvrDeviceInfoV30 = new NET_DVR_DEVICEINFO_V30();
        if (null == m_oNetDvrDeviceInfoV30) {
            Log.e(TAG, "HKNetDvrDeviceInfoV30 new is failed!");
            return -1;
        }

        String strIP = camera.address;
        int nPort = camera.port;
        String strUser = camera.account;
        String strPsd = camera.password;
        // call NET_DVR_Login_v30 to login on, port 8000 as default
        int iLogID = HCNetSDK.getInstance().NET_DVR_Login_V30(strIP, nPort,
                strUser, strPsd, m_oNetDvrDeviceInfoV30);
        if (iLogID < 0) {
            Log.e(TAG, "NET_DVR_Login is failed!Err:"
                    + HCNetSDK.getInstance().NET_DVR_GetLastError());
            return -1;
        }
        if (m_oNetDvrDeviceInfoV30.byChanNum > 0) {
            m_iStartChan = m_oNetDvrDeviceInfoV30.byStartChan;
            m_iChanNum = m_oNetDvrDeviceInfoV30.byChanNum;
        } else if (m_oNetDvrDeviceInfoV30.byIPChanNum > 0) {
            m_iStartChan = m_oNetDvrDeviceInfoV30.byStartDChan;
            m_iChanNum = m_oNetDvrDeviceInfoV30.byIPChanNum
                    + m_oNetDvrDeviceInfoV30.byHighDChanNum * 256;
        }
        Log.i(TAG, "NET_DVR_Login is Successful!");

        return iLogID;
    }

    private RealPlayCallBack getRealPlayerCbf() {
        RealPlayCallBack cbf = new RealPlayCallBack() {
            public void fRealDataCallBack(int iRealHandle, int iDataType,
                                          byte[] pDataBuffer, int iDataSize) {

                if (HCNetSDK.NET_DVR_SYSHEAD == iDataType) {
                    if (m_iPort >= 0) {
                        return;
                    }
                    m_iPort = Player.getInstance().getPort();
                    Player.getInstance().setStreamOpenMode(m_iPort,
                            Player.STREAM_REALTIME);
                    Player.getInstance().openStream(m_iPort, pDataBuffer,
                            iDataSize, 2 * 1024 * 1024);
                    Player.getInstance().setDisplayBuf(m_iPort, 6);
                    setDecodeCB();//设置解码回调
                    Player.getInstance().play(m_iPort, null);
                } else
                    Player.getInstance().inputData(m_iPort, pDataBuffer, iDataSize);
            }
        };
        return cbf;
    }


    private void setDecodeCB() {
        Player.getInstance().setDecodeCB(m_iPort, new PlayerCallBack.PlayerDecodeCB() {

            @Override
            public void onDecode(int nPort, final byte[] data,
                                 int nDataLen, int nWidth, int nHeight, int nFrameTime,
                                 int nDataType, int arg7) {
                try {
                    if (nDataType == 3) {
                        byte[] i420bytes;
                        i420bytes = swapYV12toI420(data, nWidth, nHeight);
                        if (i420bytes != null) {
                            callback.afterCall(i420bytes.length, i420bytes, nWidth, nHeight, nFrameTime);
                        }
                    }

                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
            }

        });

    }

    private byte[] i420bytes = null;

    private byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
        if (null == i420bytes) {
            i420bytes = new byte[yv12bytes.length];
        }
        int nTemp = width * height;
        System.arraycopy(yv12bytes, nTemp + (nTemp / 4), i420bytes, nTemp, nTemp / 4);
        System.arraycopy(yv12bytes, nTemp, i420bytes, nTemp + (nTemp / 4), nTemp / 4);
        System.arraycopy(i420bytes, nTemp, yv12bytes, nTemp, nTemp / 2);

        return yv12bytes;
    }
}
